use std::sync::atomic::{AtomicU8, Ordering};

use dashmap::DashMap;
use tokio::sync::oneshot;

use crate::error::{ec, new_err_msg, AppErr};

use super::message::Message;

pub struct MessageRouter {
    global_seq: AtomicU8,
    // key (type << 8) + seq
    msg_map: DashMap<u16, oneshot::Sender<Message>>,
}


impl MessageRouter {

    pub fn new() -> MessageRouter {
        MessageRouter {
            global_seq: AtomicU8::new(0),
            msg_map: DashMap::new(),
        }
    }

    pub fn get_seq(&self) -> u8 {
        self.global_seq.fetch_add(1, Ordering::SeqCst)
    }

    pub fn post(&self, msg: Message) -> Result<(), AppErr> {
        let key = ((msg.msg_type as u16) << 8) + msg.seq as u16; 
        let (_, tx) = self
            .msg_map
            .remove(&key)
            .ok_or(new_err_msg(ec::MSG_NO_RECV, "no receiver"))?;
        _ = tx.send(msg);
        Ok(())
    }

    pub fn expect_rx(&self, seq: u8, msg_type: u8) -> oneshot::Receiver<Message> {
        let key = ((msg_type as u16) << 8) + seq as u16; 
        let (tx, rx) = oneshot::channel();
        self.msg_map.insert(key, tx);
        rx
    }
}
